/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @brief Define some Hash Functions.
 *
 * @see http://www.partow.net/programming/hashfunctions/#RSHashFunction
 *
 * @author  WXQ#XDU
 * @date    2024.11
 */

#include <stddef.h>

#include "../include/amcc_hashmap.h"

static int  use_hash_func  =
#if   defined  HASH_JAVA
        0
#elif defined  HASH_BKDR
        1
#elif defined  HASH_PJW
        2
#else
        3
#endif
        ;

// In OpenJDK, the hash code of a string is computed as
//    s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
// using int arithmetic, where s[i-1] is the i_th character of the string,
// n is the length of the string, and "^" indicates exponentiation.
// (The hash value of the empty string is zero.)
//
static t_hashcode  hashcode_java(const char* str){
    int h = 0;
    while ( * str ) {
        h = 31 * h + ((*str++) & 0xff);
    }
    return (t_hashcode)(h & 0X7FFFFFFF);
}

// BKDR Hash Function.
//
// From "The C Programming Language",  Brain Kernighan, Dennis Ritchie
// :::: hashcode_java comes this function.
//
static t_hashcode hashcode_BKDR(const char * str) {
    unsigned int seed = 131;  // 31 131 1313 13131 131313 etc...
    unsigned int hash = 0;
    while ( * str) {
        hash = hash * seed + ((*str++) & 0xff);
    }
    return (hash & 0x7FFFFFFF );
}

// PJW Hash Function.
//
// This hash algorithm is based on work by Peter J. Weinberger of Renaissance Technologies.
// The book "Compilers (Principles, Techniques and Tools)" by Aho etc.,
// recommends the use of hash functions that employ the hashing methodology
// found in this particular algorithm.
//
// This algorithm is also introduced in our text book.
//
static t_hashcode  hashcode_PJW(const char * str) {
    unsigned int bitsInSizeType = (unsigned int)(sizeof(size_t) * 8);
    unsigned int threeQuarters  = (unsigned int)((bitsInSizeType * 3 ) / 4 );
    unsigned int oneEighth      = (unsigned int)(bitsInSizeType / 8 );
    unsigned int highBits       = (unsigned int)(-1) << (bitsInSizeType - oneEighth);
    unsigned int hash  = 0;
    unsigned int test = 0;
    while ( * str) {
        hash = (hash << oneEighth) + ((*str++) & 0xff);
        if ((test = hash & highBits) != 0 ) {
            hash ^= (test >> threeQuarters);
            hash &= (~ highBits);
        }
    }
    return (hash & 0X7FFFFFFF );
}

// An interface of underlying hash function
t_hashcode amcc_hashcode(const char * str) {
    if (NULL == str) return 0;
    switch ( use_hash_func ) {
        case 0:   return hashcode_java(str);
        case 1:   return hashcode_BKDR(str);
        default:  return hashcode_PJW(str);
    }

}
